package com.biz.primus.ms.payment.channel.allinpay.lang;

import com.biz.primus.base.exception.lang.SignException;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.security.*;
import java.security.cert.Certificate;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * RSA
 *
 * @author JKLiues
 * @date 2017年11月13日
 */
@Slf4j
public class RSA {

    private static final String ALGORITHM = "SHA1WithRSA";
    private static final String KEY_STORE_TYPE = "PKCS12";

    /**
     * RSA 加密
     *
     * @param pfx     签名证书路径
     * @param alias   别称
     * @param pwd     密码
     * @param signSrc 加密字段
     * @return String
     */
    public static String encrypt(String pfx, String pwd, String alias, String signSrc) {
        //获得私钥并签名
        PrivateKey privateKey;
        KeyPair keyPair;
        try {
            KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
            keyStore.load(new FileInputStream(pfx), pwd.toCharArray());
            Key key = keyStore.getKey(alias, pwd.toCharArray());
            if (key instanceof PrivateKey) {
                Certificate cert = keyStore.getCertificate(alias);
                keyPair = new KeyPair(cert.getPublicKey(), (PrivateKey) key);
                privateKey = keyPair.getPrivate();
                Signature signature = Signature.getInstance(ALGORITHM, new BouncyCastleProvider());
                signature.initSign(privateKey);
                signature.update(signSrc.getBytes());
                byte[] signBytes = signature.sign();
                return Base64.encodeBase64String(signBytes);
            }
        } catch (Exception e) {
            log.error("RSA加密失败{}", e.getMessage());
        }
        return null;
    }


    /**
     * RSA 加密
     *
     * @param pfx    签名证书路径
     * @param alias  别称
     * @param pwd    密码
     * @param params 加密对象需要加密的字段
     * @param obj    加密对象
     * @return String
     */
    public static String encrypt(String pfx, String pwd, String alias, Collection<String> params, Object obj) {
        Class<?> aClass = obj.getClass();
        List<String> kvPair = Lists.newArrayList();
        try {
            for (String name : params) {
                Field declaredField = aClass.getDeclaredField(name);
                declaredField.setAccessible(true);
                Object o = declaredField.get(obj);
                if (Objects.nonNull(o)&&StringUtils.isNotBlank(o.toString())) {
                    kvPair.add(String.format("%s=%s", name, String.valueOf(o)));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SignException("access to sign object with exception " + e.getMessage());
        }
        if (CollectionUtils.isEmpty(kvPair)) {
            throw new SignException("access to sign object with none params");
        }
        String join = StringUtils.join(kvPair, "&");
        return encrypt(pfx, pwd, alias, join);
    }
}